package com.suixin.learn.persistence.factory;

import com.suixin.learn.persistence.pojo.Configuration;
import com.suixin.learn.persistence.pojo.MappedStatement;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.util.List;

public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <E> List<E> selectList(String statementId, Object... params) throws Exception {
        //使用executor调用query方法
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
        List<Object> list = simpleExecutor.query(configuration, mappedStatement, params);
        return (List<E>) list;
    }

    @Override
    public <E> E selectOne(String statementId, Object... params) throws Exception {
        List<Object> objects = selectList(statementId, params);
        if(objects.size() == 1){
            return (E)objects.get(0);
        }else if(objects.size() > 1){
            throw new RuntimeException("查询到的结果过多");
        }else{
            return null;
        }

    }

    @Override
    public int update(String statementId, Object... params) throws Exception {
        return doUpdate(statementId, params);
    }

    private int doUpdate(String statementId, Object[] params) throws Exception {
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
        return simpleExecutor.update(configuration, mappedStatement, params);
    }

    @Override
    public int delete(String statementId, Object... params) throws Exception {
        return doUpdate(statementId, params);
    }

    @Override
    public int insert(String statementId, Object... params) throws Exception {
        return doUpdate(statementId, params);
    }

    @Override
    public <T> T getMapper(Class<?> mapperClass) {

        return (T)Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                String name = method.getDeclaringClass().getName();
                String statementId = name+"."+method.getName();
                MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
                switch(mappedStatement.getCommandType()){
                    case "select":
                        if(method.getGenericReturnType() instanceof ParameterizedType){

                            return selectList(statementId,args);
                        }

                        return selectOne(statementId,args);
                    case "update":
                        return update(statementId,args);
                    case "insert":
                        return insert(statementId,args);
                    case "delete":
                        return delete(statementId,args);
                    default:
                       return doUpdate(statementId,args);

                }

            }
        });

    }
}
